package com.seadragon.apps.doctorcard.service.impl;

import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_ALREADY_FRIEND;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_CAN_NOT_SEND_REQUEST_TO_YOURSELF;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_CONTACT_NOT_EXIST;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_FAIL_TO_SAVE_FRIEND;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_FAIL_TO_SAVE_REQUEST;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_NOT_REQUEST_RECIPIENT;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.ERROR_CODE_REQUEST_ALREADY_EXIST;
import static com.seadragon.apps.doctorcard.model.DoctorCardConstants.RETURN_SUCCESS;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.seadragon.apps.doctorcard.model.Contact;
import com.seadragon.apps.doctorcard.model.Friend;
import com.seadragon.apps.doctorcard.model.Request;
import com.seadragon.apps.doctorcard.model.RequestStatus;
import com.seadragon.apps.doctorcard.repository.ContactRepository;
import com.seadragon.apps.doctorcard.repository.RequestRepository;
import com.seadragon.apps.doctorcard.service.FriendService;
import com.seadragon.apps.doctorcard.service.RequestService;

@Service("requestService")
@Transactional
public class RequestServiceImpl implements RequestService {
	private static final Logger logger = LoggerFactory.getLogger(RequestServiceImpl.class);
	@Autowired
	private RequestRepository requestRepository;
	
	@Autowired
	private ContactRepository contactRepository;
	
	@Autowired
	private FriendService friendService;
	

	private SimpMessagingTemplate template;

	@Autowired
	public RequestServiceImpl(SimpMessagingTemplate template){
		this.template = template;
	}
	
	@Override
	public void rejectRequest(Request request) {
		Request requestAttached = requestRepository.findOne(request.getId());
		requestAttached.setStatus(RequestStatus.RequstRejected);
		requestRepository.save(requestAttached);
	}

	@Override
	public List<Contact> findAllRequests(Contact contact) {
		List<Request> requests = requestRepository.findAllRequests(contact);
		List<Contact> contacts = new ArrayList<Contact>();
		for(Request request : requests){
			Contact c = null;
			if(request.getSender().getId() == contact.getId()){
				c = request.getRecipient();
				c.setStatus(request.getStatus());
			}else{
				c = request.getSender();
				c.setStatus(request.getStatus());
			}
			contacts.add(c);				
		}
		return contacts;

	}

	@Override
	public List<Request> findAllRequestsByStatus(Contact sender, RequestStatus status) {
		return requestRepository.findAllRequestsByStatus(sender, status);
	}

	@Override
	public List<Contact> findAllRequestsReceivedByStatus(Contact recipient, RequestStatus status){
		List<Request> requestsReceived = requestRepository.findAllRequestsReceivedByStatus(recipient, status);
		List<Contact> contacts = new ArrayList<Contact>();
		for(Request request : requestsReceived){
			Contact contact = request.getSender();
			contact.setStatus(request.getStatus());
			contacts.add(contact);
		}
		return contacts;
	}
	
	@Override
	public List<Request> findAllRequestsSent(Contact sender) {
		return requestRepository.findAllRequestsSent(sender);
	}

	@Override
	public List<Request> findAllRequestsReceived(Contact recipient) {
		return requestRepository.findAllRequestsReceived(recipient);
	}

	@Override
	public int sendRequest(Contact sender, Request request) {
		if(sender.getId() == request.getRecipient().getId()){
			return ERROR_CODE_CAN_NOT_SEND_REQUEST_TO_YOURSELF;
		}
		Contact senderAttached = contactRepository.findOne(sender.getId());
		Contact recipientAttached = contactRepository.findOne(request.getRecipient().getId());
		if(recipientAttached == null){
			return ERROR_CODE_CONTACT_NOT_EXIST;
		}
		Friend friend = friendService.findByTwoContacts(senderAttached, recipientAttached);
		if(friend != null){
			return ERROR_CODE_ALREADY_FRIEND;
		}
		Request requestSaved = requestRepository.findBySenderAndRecipient(senderAttached, recipientAttached);
		if(requestSaved != null) return ERROR_CODE_REQUEST_ALREADY_EXIST;
		
		request.setSender(senderAttached);
		request.setRecipient(recipientAttached);
		request.setStatus(RequestStatus.RequestSent);
		request.setDateRequested(new Date());
		try{
			requestRepository.save(request);
			template.convertAndSend("/queue/newlyReceivedRequests-" + recipientAttached.getId(), this.countByNewlyReceivedRequests(recipientAttached));
			return RETURN_SUCCESS;
		}catch(Exception ex){
			logger.error("Failed to save the request!", ex.getMessage());
			return ERROR_CODE_FAIL_TO_SAVE_REQUEST;
		}
	}

	@Override
	public boolean exists(Contact sender, Contact recipient){
		Request request = requestRepository.findBySenderAndRecipient(sender, recipient);
		if(request == null) return false;
		return true;
	}
	
	@Override
	public int acceptRequest(Contact recipient, Request request) {
		Request requestSaved = requestRepository.findBySenderAndRecipient(request.getSender(), request.getRecipient());
		if(recipient.getId() != requestSaved.getRecipient().getId()){
			return ERROR_CODE_NOT_REQUEST_RECIPIENT;
		}
		requestSaved.setStatus(RequestStatus.RequestAccepted);
		requestSaved.setDateResponded(new Date());
		requestRepository.save(requestSaved);
		
		Friend friendSaved = friendService.save(new Friend(requestSaved.getSender(), requestSaved.getRecipient()));
		if(friendSaved == null){
			return ERROR_CODE_FAIL_TO_SAVE_FRIEND;
		}
		return RETURN_SUCCESS;
	}
	
	@Override
	public int countByNewlyReceivedRequests(Contact recipient){
		return requestRepository.countByRecipientAndStatus(recipient, RequestStatus.RequestSent);
	}
}
